#pragma once
#include "muduo/net/EventLoopThread.h"
#include "muduo/net/TcpClient.h"
#include <memory>
#include <iostream>
#include "channel.hpp"
#include "ansyncpool.hpp"
#include "../mqcommom/threadpool.hpp"
#include "../mqcommom/helper.hpp"
#include "../mqcommom/proto.pb.h"
#include "muduo/proto/dispatcher.h"
#include "muduo/proto/codec.h"
namespace ns_rabbitmq
{
    class Connection
    {
        using BasicConsumerResponseptr = std::shared_ptr<BasicConsumerResponse>;
        using BasicCommResponseptr = std::shared_ptr<BasicCommResponse>;
        using ProtobufCodecPtr = std::shared_ptr<ProtobufCodec>;

    public:
        Connection(const std::string &serverip, const int serverport, const AnsyncPoolPtr &ansyncpool)
            : _latch(1),
              _client(ansyncpool->loopthread.startLoop(), muduo::net::InetAddress(serverip, serverport), "Connection"),
              _dispatcher(std::bind(&Connection::onUnknownMessage, this, std::placeholders::_1, 
              std::placeholders::_2, std::placeholders::_3)),
              _codec(std::make_shared<ProtobufCodec>(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, 
              std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))), 
              _pools(ansyncpool)
            ,_channels(std::make_shared<ChannelManager>())
        {
            // 为派发器注册方法
            _dispatcher.registerMessageCallback<BasicConsumerResponse>(std::bind(&Connection::OnBasicConsumer, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            _dispatcher.registerMessageCallback<BasicCommResponse>(std::bind(&Connection::OnBasicComm, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));


            // 设置连接方法
            _client.setConnectionCallback(std::bind(&Connection::onConnection, this, std::placeholders::_1));

            // 设置消息处理，协议解析
            _client.setMessageCallback(std::bind(&ProtobufCodec::onMessage, _codec.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

            _client.connect();
            _latch.wait(); // 阻塞等待，直到连接建立成功
        }
        ChannelPtr OpenChannel()
        {
            ChannelPtr channel = _channels->CreateChannel(_conn, _codec);
            bool ret = channel->OpenChannel();
            if (!channel.get() && ret)
            {
               ELOG("创建信道失败");
                return ChannelPtr();
            }
            return channel;
        }

        void CloseChannel(const ChannelPtr &channel)
        {
            channel->CloseChannel();
            _channels->RemoveChannel(channel->cid());
        }

    private:
        // 建立连接和断开才调用，唤醒阻塞
        void onConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            if (conn->connected())
            {
                _latch.countDown();
                _conn = conn;
            }
            else
            {
                _conn.reset();
                std::cout << "连接断开" << std::endl;
            }
        }

        void onUnknownMessage(const muduo::net::TcpConnectionPtr &conn, const MessagePtr &message, muduo::Timestamp)
        {
            std::cout << "onUnknownMessage: " << message->GetTypeName();
            conn->shutdown();
        }

        void OnBasicConsumer(const muduo::net::TcpConnectionPtr &conn, const BasicConsumerResponseptr &message, muduo::Timestamp t)
        {
            // 找到连接的信道
            ChannelPtr channel = _channels->GetChannel(message->cid());
            if (!channel.get())
            {
                DLOG("不存在信道%s", message->cid().c_str());
                return;
            }
            // 构建任务
            _pools->pool.push([channel,message]() {
                channel->Consume(message);
            });
        }

        void OnBasicComm(const muduo::net::TcpConnectionPtr &conn, const BasicCommResponseptr &message, muduo::Timestamp t)
        {
            // 找到连接的信道
            ChannelPtr channel = _channels->GetChannel(message->cid());
            if (!channel.get())
            {
                DLOG("不存在信道%s", message->cid().c_str());
                return;
            }
            // 添加进基础响应
            channel->PutBasicResponse(message);
        }

    private:
        muduo::CountDownLatch _latch;
        muduo::net::TcpConnectionPtr _conn;
        muduo::net::TcpClient _client;

        ProtobufDispatcher _dispatcher; // 事件派发器
        ProtobufCodecPtr _codec;        // 协议处理器

        AnsyncPoolPtr _pools;
        ChannelManagerPtr _channels;
    };
    using ConnectionPtr=std::shared_ptr<Connection>;

}


// namespace ns_rabbitmq
// {
//    class Connection {
//     public:
//      using BasicConsumerResponseptr = std::shared_ptr<BasicConsumerResponse>;
//         using BasicCommResponseptr = std::shared_ptr<BasicCommResponse>;
//         using ProtobufCodecPtr = std::shared_ptr<ProtobufCodec>;
//         Connection(const std::string &sip, int sport, const AsyncWorker::ptr &worker):
//             _latch(1), _client(worker->loopthread.startLoop(), muduo::net::InetAddress(sip, sport), "Client"),
//             _dispatcher(std::bind(&Connection::onUnknownMessage, this, std::placeholders::_1, 
//                 std::placeholders::_2, std::placeholders::_3)),
//             _codec(std::make_shared<ProtobufCodec>( std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, 
//                 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))),
//             _worker(worker),
//             _channel_manager(std::make_shared<ChannelManager>()){

//             _dispatcher.registerMessageCallback<BasicCommResponse>(std::bind(&Connection::basicResponse, this, 
//                 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
                
//             _dispatcher.registerMessageCallback<BasicConsumerResponse>(std::bind(&Connection::consumeResponse, this, 
//                 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

//             _client.setMessageCallback(std::bind(&ProtobufCodec::onMessage, _codec.get(),
//                 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
//             _client.setConnectionCallback(std::bind(&Connection::onConnection, this, std::placeholders::_1));      

            
//             _client.connect();
//             _latch.wait();//阻塞等待，直到连接建立成功
//         }
//        ChannelPtr openChannel() {
//             ChannelPtr channel = _channel_manager->CreateChannel(_conn, _codec);
//             bool ret = channel->OpenChannel();
//             if (ret == false) {
//                 return ChannelPtr();
//             }
//             return channel;
//         }
//         void closeChannel(const ChannelPtr &channel) {
//             channel->closeChannel();
//             _channel_manager->RemoveChannel(channel->cid());
//         }
//     private:
//         void basicResponse(const muduo::net::TcpConnectionPtr& conn, const BasicCommResponseptr& message, muduo::Timestamp) {
//             //1. 找到信道
//             ChannelPtr channel = _channel_manager->GetChannel(message->cid());
//             if (channel.get() == nullptr) {
//                 return;
//             }
//             //2. 将得到的响应对象，添加到信道的基础响应hash_map中
//             channel->PutBasicResponse(message);
//         }
//         void consumeResponse(const muduo::net::TcpConnectionPtr& conn, const BasicConsumerResponseptr& message, muduo::Timestamp){
//             //1. 找到信道
//            ChannelPtr channel = _channel_manager->GetChannel(message->cid());
//             if (channel.get() == nullptr) {
//                 return;
//             }
//             //2. 封装异步任务（消息处理任务），抛入线程池
//             _worker->pool.push([channel, message](){
//                 channel->Consume(message);
//             });
//         }
//         void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn, const MessagePtr& message, muduo::Timestamp) {
//             conn->shutdown();
//         }
//         void onConnection(const muduo::net::TcpConnectionPtr&conn){
//             if (conn->connected()) {
//                 _latch.countDown();//唤醒主线程中的阻塞
//                 _conn = conn;
//             }else {
//                 //连接关闭时的操作
//                 _conn.reset();
//             }
//         }
//     private:
//         muduo::CountDownLatch _latch;//实现同步的
//         muduo::net::TcpConnectionPtr _conn;//客户端对应的连接
//         muduo::net::TcpClient _client;//客户端
//         ProtobufDispatcher _dispatcher;//请求分发器
//         ProtobufCodecPtr _codec;//协议处理器

//         AnsyncPoolPtr _worker;
//         ChannelManagerPtr _channel_manager;
// };
//     using ConnectionPtr=std::shared_ptr<Connection>;

// }
